using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Admin.NET.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;
using Microsoft.AspNetCore.Http;
using System.Text;
using System.Web;
using System.ComponentModel;
using System.Data;
namespace @Model.NameSpace
{
    /// <summary>
    /// @(@Model.BusName)服务
    /// </summary>
    [ApiDescriptionSettings("@Model.ModuleName", Name = "@Model.ClassName", Order = 100)]
    [Route("api/[Controller]")]
    public class @(@Model.ClassName)Service : I@(@Model.ClassName)Service, IDynamicApiController, ITransient
    {
        private readonly IRepository<@(@Model.ClassName),@(@Model.DatabaseName)> _@(@Model.CamelizeClassName)Rep;
@foreach (var column in Model.TableField){
if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){
        @:private readonly IRepository<@(@column.FkEntityName)> _@(@column.LowerFkEntityName)Rep;
}
}
        private readonly IRepository<SysDictType, MasterDbContextLocator> _sysDictTypeRep;
        private readonly IRepository<SysDictData, MasterDbContextLocator> _sysDictDataRep;
        private readonly ISysExcelTemplateService _sysExcelTemplateService;
        private readonly static object _lock = new();
@if(@Model.IsFile)
{
        @:private readonly IRepository<SysFile> _sysFileInfoRep;
}

        public @(@Model.ClassName)Service(
@foreach (var column in Model.TableField){
if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){
            @:IRepository<@(@column.FkEntityName)> @(@column.LowerFkEntityName)Rep,
}
}
            IRepository<@(@Model.ClassName),@(@Model.DatabaseName)> @(@Model.CamelizeClassName)Rep
@if(@Model.IsFile)
{
            @:,IRepository<SysFile> sysFileInfoRep,
}
            ,IRepository<SysDictType, @(@Model.DatabaseName)> sysDictTypeRep
            ,IRepository<SysDictData, @(@Model.DatabaseName)> sysDictDataRep
            ,ISysExcelTemplateService sysExcelTemplateService
        )
        {
@foreach (var column in Model.TableField){
if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){
            @:_@(@column.LowerFkEntityName)Rep = @(@column.LowerFkEntityName)Rep;
}
}
            _@(@Model.CamelizeClassName)Rep = @(@Model.CamelizeClassName)Rep;
@if(@Model.IsFile)
{
        @:_sysFileInfoRep = sysFileInfoRep;
}
         _sysDictTypeRep = sysDictTypeRep;
         _sysDictDataRep = sysDictDataRep;
         _sysExcelTemplateService = sysExcelTemplateService;
        }

        /// <summary>
        /// 分页查询@(@Model.BusName)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/page")]
        [HttpGet("page")]
        public async Task<PageResult<@(@Model.ClassName)Output>> Page([FromQuery] @(@Model.ClassName)Search input)
        {
            var @(@Model.CamelizeClassName)s = await _@(@Model.CamelizeClassName)Rep.DetachedEntities
@foreach (var column in Model.TableField){    
if (@column.QueryWhether == "Y"){
if (@column.NetType == "string"){
if (@column.QueryType == "like"){
                                     @:.Where(!string.IsNullOrEmpty(input.@column.ColumnName), u => EF.Functions.Like(u.@(@column.ColumnName), $"%{input.@(@column.ColumnName).Trim()}%"))
} else {
                                     @:.Where(!string.IsNullOrEmpty(input.@column.ColumnName), u => u.@(@column.ColumnName) @column.QueryType input.@(@column.ColumnName))
}
} else {
if (@column.EffectType == "fk"){                
                                     @:.Where(input.@column.ColumnName > 0, u => u.@(@column.ColumnName) @column.QueryType input.@(@column.ColumnName))
}

  if (@column.EffectType == "datepicker" && @column.QueryType == "between"){     
  
                                     @:.Where(input.@column.ColumnName!=null, u => u.@(@column.ColumnName)>=  Convert.ToDateTime(input.@(@column.ColumnName)[0]+" 00:00:00") && u.@(@column.ColumnName)<= Convert.ToDateTime(input.@(@column.ColumnName)[1]+" 23:59:59"))
        }
        else  if (@column.EffectType == "datetimepicker" && @column.QueryType == "between"){     
  
                                     @:.Where(input.@column.ColumnName!=null, u => u.@(@column.ColumnName)>=  Convert.ToDateTime(input.@(@column.ColumnName)[0]) && u.@(@column.ColumnName)<= Convert.ToDateTime(input.@(@column.ColumnName)[1]))
        }

else {
                                     @:.Where(input.@column.ColumnName != null, u => u.@(@column.ColumnName) @column.QueryType input.@(@column.ColumnName))
}
}
}
}
                                     .OrderBy(PageInputOrder.OrderBuilder<@(@Model.ClassName)Search>(input))
                                     .ProjectToType<@(@Model.ClassName)Output>()
                                     .ToADPagedListAsync(input.PageNo, input.PageSize);
@if(@Model.IsFile)
{
            @:@(@Model.CamelizeClassName)s.Rows.ToList().ForEach(item =>
            @:{
foreach (var column in Model.FileTableField){  
                @:item.@(@column.ColumnName) = item.@(@column.ColumnName)_Str.GetFiles(_sysFileInfoRep);
}
            @:});
}
            return @(@Model.CamelizeClassName)s;
        }

        /// <summary>
        /// 不分页查询@(@Model.BusName)列表
        /// </summary>
        /// <param name="input">@(@Model.BusName)查询参数</param>
        /// <returns>(@Model.BusName)实例列表</returns>
        [Description("@Model.ClassName/listNonPage")]
        [HttpGet("listNonPage")]
        public async Task<List<@(@Model.ClassName)Output>> ListNonPageAsync([FromQuery] @(@Model.ClassName)SearchNonPage input)
        {
@foreach (var column in Model.TableField)
{    
    if (@column.QueryWhether == "Y")
    {
        
         if(@column.NetType == "string" && @column.QueryType != "isNotNull"){
            @:var p@(@column.ColumnName) = input.@(@column.ColumnName)?.Trim() ?? "";
        } else if(@column.QueryType != "isNotNull"){
            @:var p@(@column.ColumnName) = input.@(@column.ColumnName);
        }
    }
}
            var @(@Model.CamelizeClassName)s = await _@(@Model.CamelizeClassName)Rep.DetachedEntities
@foreach (var column in Model.TableField)
{    
    if (@column.QueryWhether == "Y") 
    {
        if(@column.QueryType == "isNotNull")
        {
                @:.Where(u => u.@(@column.ColumnName) != null)
        }
        else if (@column.NetType == "string") 
        {
            if (@column.QueryType == "like") 
            {
                @:.Where(!string.IsNullOrEmpty(p@(@column.ColumnName)), u => EF.Functions.Like(u.@(@column.ColumnName), $"%{p@(@column.ColumnName)}%")) 
            } else 
            {
                @:.Where(!string.IsNullOrEmpty(p@(@column.ColumnName)), u => u.@(@column.ColumnName) @column.QueryType p@(@column.ColumnName))
            }
        } else if (@column.EffectType == "datepicker"&&@column.QueryType == "between") 
        {      

             @:.Where(input.@column.ColumnName!=null, u => u.@(@column.ColumnName)>=  Convert.ToDateTime(input.@(@column.ColumnName)[0]+" 00:00:00") && u.@(@column.ColumnName)<= Convert.ToDateTime(input.@(@column.ColumnName)[1]+" 23:59:59"))

        }  else  if (@column.EffectType == "datetimepicker" && @column.QueryType == "between"){     
  
           @:.Where(input.@column.ColumnName!=null, u => u.@(@column.ColumnName)>=  Convert.ToDateTime(input.@(@column.ColumnName)[0]) && u.@(@column.ColumnName)<= Convert.ToDateTime(input.@(@column.ColumnName)[1]))
        }else if (@column.EffectType == "fk") 
        {                
                @:.Where(p@(@column.ColumnName) > 0, u => u.@(@column.ColumnName) @column.QueryType p@(@column.ColumnName))
        } else {
                @:.Where(p@(@column.ColumnName) != null, u => u.@(@column.ColumnName) @column.QueryType p@(@column.ColumnName))
        }
    }
}           
            .OrderBy(PageInputOrder.OrderNonPageBuilder(input))
            .ProjectToType<@(@Model.ClassName)Output>()
            .ToListAsync();
@if(@Model.IsFile)
{
            @:@(@Model.CamelizeClassName)s.ForEach(item =>
            @:{
    foreach (var column in Model.FileTableField){  
                @:item.@(@column.ColumnName) = item.@(@column.ColumnName)_Str.GetFiles(_sysFileInfoRep);
    }
            @:});
}
            return @(@Model.CamelizeClassName)s;
        }


        /// <summary>
        /// 增加@(@Model.BusName)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/add")]
        [HttpPost("add")]
        public async Task Add(Add@(@Model.ClassName)Input input)
        {
            var @(@Model.CamelizeClassName) = input.Adapt<@(@Model.ClassName)>();
                        //验证
            await CheckExisit(@(@Model.CamelizeClassName));
            await _@(@Model.CamelizeClassName)Rep.InsertAsync(@(@Model.CamelizeClassName));
        }

        /// <summary>
        /// 删除@(@Model.BusName)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/delete")]
        [HttpPost("delete")]
        public async Task Delete(Delete@(@Model.ClassName)Input input)
        {
@foreach (var column in Model.TableField){
if (@column.ColumnKey == "True"){
            @:var @(@Model.CamelizeClassName) = await _@(@Model.CamelizeClassName)Rep.FirstOrDefaultAsync(u => u.@(@column.ColumnName) == input.@(@column.ColumnName));
}
}
            await _@(@Model.CamelizeClassName)Rep.DeleteAsync(@(@Model.CamelizeClassName));
        }

        /// <summary>
        /// 更新@(@Model.BusName)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/edit")]
        [HttpPost("edit")]
        public async Task Update(Update@(@Model.ClassName)Input input)
        {
            var isExist = await _@(@Model.CamelizeClassName)Rep.AnyAsync(u => u.Id == input.Id, false);
            if (!isExist) throw Oops.Oh(ErrorCode.D1002);

            var @(@Model.CamelizeClassName) = input.Adapt<@(@Model.ClassName)>();
            //验证
            await CheckExisit(@(@Model.CamelizeClassName),true);
            await _@(@Model.CamelizeClassName)Rep.UpdateAsync(@(@Model.CamelizeClassName),ignoreNullValues:true);
        }

        /// <summary>
        /// 获取@(@Model.BusName)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/detail")]
        [HttpGet("detail")]
        public async Task<@(@Model.ClassName)Output> Get([FromQuery] Querye@(@Model.ClassName)Input input)
        {
@foreach (var column in Model.TableField){
if (@column.ColumnKey == "True"){
            @:return (await _@(@Model.CamelizeClassName)Rep.DetachedEntities.FirstOrDefaultAsync(u => u.@(@column.ColumnName) == input.@(@column.ColumnName))).Adapt<@(@Model.ClassName)Output>();
}
}            
        }

        /// <summary>
        /// 获取@(@Model.BusName)列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Description("@Model.ClassName/list")]
        [HttpGet("list")]
        public async Task<List<@(@Model.ClassName)Output>> List([FromQuery] @(@Model.ClassName)Input input)
        {
            return await _@(@Model.CamelizeClassName)Rep.DetachedEntities.ProjectToType<@(@Model.ClassName)Output>().ToListAsync();
        }    
@foreach (var column in Model.TableField){
if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){
        @:
        @:/// <summary>
        @:/// 获取@(@column.FkEntityName)列表
        @:/// </summary>
        @:/// <returns></returns>
        @:[HttpGet("fk@(@column.FkEntityName)")]
        @:public async Task<dynamic> Fk@(@column.FkEntityName)List()
        @:{
            @:var list = await _@(@column.LowerFkEntityName)Rep.DetachedEntities.ToListAsync();
            @:return list.Select(e => new {Code = e.Id, Name = e.@(@column.FkColumnName)});
        @:}
}
}
         /// <summary>
        /// Excel模板导入@(@Model.BusName)功能
        /// </summary>
        /// <param name="file">Excel模板文件</param>
        /// <param name="importExcelType">Excel导入方式</param>
        /// <returns>导入的记录数</returns>
        [HttpPost("importExcel")]
        public async Task<int> ImportExcelAsync(IFormFile file, [FromQuery] ImportExcelType importExcelType)
        { 
            int _HeadStartLine = 2;//第1行是说明,第2行是列名
            int _DataStartLine = 3;//第3行开始是数据

            DataTable importDataTable = ExcelUtil.ImportExcelToDataTable(file, _HeadStartLine, _DataStartLine);
            var addList =await CommonImport(importDataTable, _DataStartLine);

            lock (_lock)
            {
                _@(@Model.CamelizeClassName)Rep.InsertAsync(addList);
               
            }
            await Task.CompletedTask;
            return addList.Count;
        }

        /// <summary>
        ///  DataTable转换实体对象列表
        /// </summary>
        /// <param name="dataTable"></param>
        /// <param name="dataStartLine">模版列名开始行</param>
        /// <returns></returns>
          private async Task<List<@(@Model.ClassName)>> CommonImport(DataTable dataTable, int dataStartLine)
        {

            var details = new List<@(@Model.ClassName)>();
            int index = dataStartLine;//模版列名开始行
            foreach (System.Data.DataRow row in dataTable.Rows)
            {
                index++;

               //导入模版定制化代码（替换模版使用）
                @Model.ImportExcelCustomizationContent
             
                details.Add(addItem);
            }
            //验证
            await CheckExisitForImport(details);
            return details;
        }

        /// <summary>
        /// 根据版本下载@(@Model.BusName)的Excel导入模板
        /// </summary>
        /// <param name="version">模板版本</param>
        /// <returns>下载的模板文件</returns>
        [Description("@Model.ClassName/downloadExcelTemplate")]
        [HttpGet("downloadExcelTemplate")]
        public IActionResult DownloadExcelTemplate([FromQuery] string version)
        {
            string _path = TemplateConst.EXCEL_TEMPLATEFILE_导入模版路径 + $"\\@Model.ClassName{TemplateConst.EXCEL_TEMPLATEFILE_导入模版名称后缀}.xlsx";
            var fileName = HttpUtility.UrlEncode($"导入模板(@Model.BusName).xlsx", Encoding.GetEncoding("UTF-8"));
            return new FileStreamResult(new FileStream(_path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
        }

        /// <summary>
        /// 根据@(@Model.BusName)查询参数导出Excel
        /// </summary>
        /// <param name="input">@(@Model.BusName)查询参数</param>
        /// <returns>导出的Excel文件</returns>
        [Description("@Model.ClassName/toExcel")]
        [HttpGet("toExcel")]
        public async Task<IActionResult> ToExcelAsync([FromQuery] @(@Model.ClassName)SearchNonPage input)
        {
            var @(@Model.CamelizeClassName)List = await ListNonPageAsync(input);
            MemoryStream ms = new();
            DataConvertUtil.ToExcelData(@(@Model.CamelizeClassName)List, _sysDictTypeRep, _sysDictDataRep, out List<string> headers, 
                out List<List<object>> data, out string sheetName);
            var excelTemplate = await _sysExcelTemplateService.GetByAppNameAndClassNameAndVersionAsync("@(@Model.ClassName)", "v1");
            if (excelTemplate != null)
            {
                ExcelUtil.ToExcel(excelTemplate.TemplateFileName, headers, data, sheetName, excelTemplate.HeadStartLine, excelTemplate.DataStartLine, ms);
            }
            else 
            {
                ExcelUtil.ToExcel(headers, data, sheetName, ms);
            }
            ms.Position = 0;
            var fileName = HttpUtility.UrlEncode($"{sheetName}[{DateTimeOffset.Now:yyyy-MM-dd}].xlsx", Encoding.GetEncoding("UTF-8"));
            return new FileStreamResult(ms, "application/octet-stream") { FileDownloadName = fileName };
        }



        

        /// <summary>
        /// 根据联合主键验证数据是否已存在-数据库
        /// </summary>
        /// <param name="input"></param>
        /// <param name="isEdit"></param>
        /// <returns></returns>
        private async Task CheckExisit( @(@Model.ClassName) input,bool isEdit=false)
        {
            bool isExist = false;

            @{
                var columnIndex = 0;
             }
            if (!isEdit)//新增
            {


                                      @foreach (var column in Model.TableField)
                                      {
                                         
                                      
                                          if (@column.WhetherUnionKey == "Y")
                                          {   
                                              columnIndex++;
                                              if (@columnIndex == 1)
                                              {
                 @://数据是否重复
                 @:isExist = await _@(@Model.CamelizeClassName)Rep.AnyAsync(u => u.@(@column.ColumnName).Equals(input.@column.ColumnName)
                                              }
                                              else
                                              {
                                                  @:&&u.@(@column.ColumnName).Equals(input.@column.ColumnName)
                                              }
                                             
                                          }

                                         
                                      }
                @if(columnIndex>0){
                           @:,false);
                           @:if (isExist) throw Oops.Oh(ErrorCode.E0001);
                 }
                 else{
                 @://没有配置联合主键，不需要验重
                 }


                                                                                                  

            }
            else//编辑
            {
                
                                      @foreach (var column in Model.TableField)
                                      {
                                          if (@column.WhetherUnionKey == "Y")
                                          {  
                                              columnIndex++;
                                              if (@columnIndex == 1)
                                              {
                 @://数据是否重复
                 @: isExist = await _@(@Model.CamelizeClassName)Rep.AnyAsync(u => u.Id == input.Id
                                              }
                                              else
                                              {
                                                  @:&&u.@(@column.ColumnName).Equals(input.@column.ColumnName)
                                              }
                                      }

                @if(columnIndex>0)
                {
                @:,false);
                @:if (isExist) throw Oops.Oh(ErrorCode.E0001);
                }
                else{
                @://没有配置联合主键，不需要验重
                }

            }

        }

        /// <summary>
        /// 根据联合主键验证数据是否已存在-导入时验证
        /// </summary>
        /// <param name="inputs"></param>
        /// <returns></returns>
        private async Task CheckExisit(List<@(@Model.ClassName)> inputs)
        {
            //导入的集合是否已存在相同数据  
            @{
                var index = 0;
                bool isCheck = false;
                string message = string.Empty;
            }
            @foreach (var column in Model.TableField)
            {
                if (@column.WhetherUnionKey == "Y")
                {
                    isCheck = true;
                                                                                                                        message += "," + @column.ColumnComment + "[{item." + @column.ColumnName + "}]";
                                                                                                                    }
            }
            @if (isCheck)
            {
                 @:if (inputs?.Count <= 0)
                 @:{
                 @:    throw Oops.Oh($"导入数据不能为空");
                 @:}


                 @://数据是否重复
                 @:var existExcelItem = inputs.GroupBy(g => new {
            }
           @foreach (var column in Model.TableField)
           {

               if (@column.WhetherUnionKey == "Y")
               {   
                   index++;
                   if (@index == 1)
                   { 
                                               @:g.@(@column.ColumnName)
                   }
                   else
                   {
                                               @:,g.@(@column.ColumnName)
                   }
                                       
                                                                                                                    }
           }
           @if (isCheck)
          {
                                               @:})
                                               @:.Where(g => g.Count() > 1)
                                               @:.Select(s => new {
           }
          @foreach (var column in Model.TableField)
          {

              if (@column.WhetherUnionKey == "Y")
              {
                  index++;
                  if (@index == 1)
                  {
                      @:g.@(@column.ColumnName)
                  }
                  else
                  {
                      @:,g.@(@column.ColumnName)
                  }

              }
          }
           @if (isCheck)
           {
                                               @:}).FirstOrDefault();
                 @:if (existExcelItem != null)
                 @:{
                   @:var @(@Model.CamelizeClassName) = existExcelItem.Adapt<@(@Model.ClassName)>();
                   @:var item= existExcelItem.Adapt<@(@Model.ClassName)>();
                   @:throw Oops.Oh($"导入的表格中，{message}已存在");
                 @:}
           }

        





            
           
        }


    }
}
